﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GmDeleteSelectionCmd.h"
#include "GbmpUiPlatformCommandIds.h"
#include "ActionDeleteSelectionCreator.h"
#include "GmDeleteSelectionUtils.h"
#include "UiCommonDialog.h"
#include "IInstance.h"
#include "ILevel.h"
#include "LevelUtils.h"
#include "GbmpUiPlatformCommandRegister.h"
#include "IStructureInstanceBuildingStoreyData.h"
#include "IDocument.h"
#include "CmdStatusUtils.h"
#include "IElementPosition.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace
{
    bool LevelsAssociatedWithInstanceStorey(gcmp::IDocument * pDoc,const std::vector<ElementId>& instanceIds,const ElementId levelId)
    {
        for (auto itr = instanceIds.begin(); itr != instanceIds.end(); ++itr)
        {
            const IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(*itr));
            if (!pInstance)
                continue;
            const IStructureInstanceBuildingStoreyData* buildingStoreyData = IStructureInstanceBuildingStoreyData::Get(pInstance);
            DBG_WARN_AND_CONTINUE_UNLESS(buildingStoreyData, L"获取的楼层信息为空",L"GDMPLab",L"2024-03-30");
            const ElementId buildingStoreyId = buildingStoreyData->GetBuildingStoreyId();
            if (buildingStoreyId==levelId)
            {
                return true;
            }
        }
        return false;
    }

    bool LevelsAssociatedWithPositionPlane(gcmp::IDocument * pDoc,const std::vector<ElementId>& instanceIds, const ElementId levelId)
    {
        for (auto itr = instanceIds.begin(); itr != instanceIds.end(); ++itr)
        {
            const IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(*itr));
            if (!pInstance)
                continue;
            const ElementId associatedPlaneId = IElementPosition::GetAssociatedPlaneId(pInstance);
            if (associatedPlaneId == levelId)
            {
                return true;
            }
        }
        return false;
    }

    // 临时使用， 等修复后， 通过标高的NewLevelDeletionComponent::CanBeDeleted实现
    bool CanBeDeleted(IDocument* pDoc, ILevel* pLevelToDelete, const std::vector<ElementId>& elemIdsToDelete, std::wstring* explanation)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLevelToDelete, L"pLevel指针无效",L"GDMPLab",L"2024-03-30");

        // 不属于任何单体的标高可以删除
        ElementId buildingId = pLevelToDelete->GetBuildingId();
        if (buildingId.IsValid() == false)
        {
            return true;
        }

        int levelCountInBuilding = 0;
        FOR_EACH(elemId, elemIdsToDelete)
        {
            ILevel* pLevel = LevelUtils::GetLevelById(pDoc, elemId);
            if (pLevel && pLevel->GetBuildingId() == buildingId)
            {
                ++levelCountInBuilding;
            }
        }
        // 不能删除属于这个单体的最后一个标高
        std::vector<const ILevel*> levels = LevelUtils::GetStoreyLevelsInBuilding(pDoc, buildingId);
        if (levels.size() == levelCountInBuilding)
        {
            if (explanation)
            {
                *explanation = GBMP_TR(L"每个单体至少保留一个楼层，如需删除，请至楼层管理中删除单体！");
            }
            return false;
        }
        return true;
    }
}

GmDeleteSelectionCmd::GmDeleteSelectionCmd(void) :GbmpCommandBase(ID_CMD_GBMP_DELETE_SELECTION)
{
}

GmDeleteSelectionCmd::~GmDeleteSelectionCmd(void)
{
}

gcmp::OwnerPtr<IAction> GmDeleteSelectionCmd::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    OwnerPtr<IAction> opAction = ActionDeleteSelectionCreator::Create(this);
    return opAction;
}

bool GmDeleteSelectionCmd::IsVisible() const
{
   CMD_ONLY_VISIBLE_IN_DOCUMENT_ENVIRONMENT
}

bool GmDeleteSelectionCmd::IsEnabled() const
{
    //TODO 这里应该根据所选元素的DeleteComponent自动判断
    if(!CommandBase::IsEnabled())
        return false;

    if(!CheckSelectedElementIsInEditMode())
        return false;

    // 剖切框不能删除
    if (CmdStatusUtils::IsSelectSectionBox())
    {
        return false;
    }

    CMD_ONLY_ENABLE_IN_DOCUMENT_ENVIRONMENT
}

bool GmDeleteSelectionCmd::PreDeletion(IDocument* pDoc, std::vector<ElementId>& elemIdsToDelete, bool& whether2Continue)
{
    whether2Continue = false;

    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空指针",L"GDMPLab",L"2024-03-30");

    GmDeleteSelectionUtils::SortLevelElevationInDeleteSet(pDoc, elemIdsToDelete);
    std::wostringstream levelStr;
    levelStr << GBMP_TR(L"以下标高:") << std::endl;

    std::vector<ElementId> instanceIds = IInstance::GetAllInstanceIds(pDoc);
    bool instanceStoreyWithLevel = false;
    bool instancePositionWithLevel = false;
    bool modelViewWithLevel = false;

    FOR_EACH(elemId, elemIdsToDelete)
    {
        ILevel* pLevel = LevelUtils::GetLevelById(pDoc, elemId);
        if (pLevel)
        {
            std::wstring explanation;
            if (CanBeDeleted(pDoc, pLevel, elemIdsToDelete, &explanation) == false)
            {
                UiCommonDialog::ShowMessageBox(GBMP_TR(L"警告"), explanation, (int)UiCommonDialog::ButtonType::OK);
                whether2Continue = false;
                return true;
            }

            if (!instancePositionWithLevel&&LevelsAssociatedWithPositionPlane(pDoc, instanceIds, elemId))
            {
                instancePositionWithLevel = true;
            }
            if (!instanceStoreyWithLevel&&LevelsAssociatedWithInstanceStorey(pDoc, instanceIds, elemId))
            {
                instanceStoreyWithLevel = true;
            }

            if (!modelViewWithLevel)
            {
                std::vector<ElementId> planViewVec = pLevel->GetAssociatedPlanViewIds();
                std::vector<ElementId> ceilingViewVec = pLevel->GetAssociatedCeilingViewIds();
                if (!planViewVec.empty() || !ceilingViewVec.empty())
                {
                    modelViewWithLevel = true;
                }
            }
            levelStr << pLevel->GetName() << std::endl;
        }
    }

    std::wstring tempStr =(instancePositionWithLevel?GBMP_TR(L"定位于该标高的构件、"):std::wstring())+(instanceStoreyWithLevel ? GBMP_TR(L"所属该标高的构件、") : std::wstring())
        +(modelViewWithLevel ? GBMP_TR(L"关联视图、") : std::wstring());

    if (!tempStr.empty())
    {
        //删除最后一个顿号
        tempStr.pop_back();
        std::wstring alarmingStr = StringUtil::FormatWString(GBMP_TR(L"删除以下标高时，%s会被删除，是否继续？\n\n"), tempStr.c_str());
        if (UiCommonDialog::ShowMessageBox(GBMP_TR(L"警告"), alarmingStr+levelStr.str(), (int)UiCommonDialog::ButtonType::OK | (int)UiCommonDialog::ButtonType::Cancel) != UiCommonDialog::ButtonType::OK)
        {
            whether2Continue = false;
            return true;
        }
    }
    whether2Continue = true;
    return true;
}

REGISTER_GM_COMMAND(GmDeleteSelectionCmd)


